import java.text.SimpleDateFormat;
import java.util.*;
import java.lang.Math;
import edu.jhu.htm.core.*;

public class MyObservationVector {

	Calendar calendar;

	final static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd aa:KK:mm");

	final static int resolution = 10;
	final static int MAX_ENTRIES = 50000;
	final static Map<String, Double> lat = new LinkedHashMap<String, Double>(MAX_ENTRIES+1, .75F, true) {
	    public boolean removeEldestEntry(Map.Entry eldest) { return size() > MAX_ENTRIES; }
	};
	final static Map<String, Double> lon = new LinkedHashMap<String, Double>(MAX_ENTRIES+1, .75F, true) {
	    public boolean removeEldestEntry(Map.Entry eldest) { return size() > MAX_ENTRIES; }
	};
	
	final double[] value;

	String trixel = null;
	
        public static HTMindexImp spindex = new HTMindexImp(resolution);

	public MyObservationVector(double[] value) { this.value = value; this.trixel = getTrixel( value[0], value[1] ); }
			
	public double distance(MyObservationVector e) {
		double[] evalues1 = e.value;
		double[] evalues2 = this.value;
		double distGeo = VincentyDistanceCalculator.getDistance(evalues1[0],evalues1[1],evalues2[0],evalues2[1]);
		return distGeo;
	}

	public double distance(String e) {
	    double[] evalues1 = new double[]{getCatLatitude(e) , getCatLongitude(e) };
		double[] evalues2 = this.value;
		double distGeo = VincentyDistanceCalculator.getDistance(evalues1[0],evalues1[1],evalues2[0],evalues2[1]);
		return distGeo;
	}

        public static double[] latLongToCartesian(double[] array){	
	        return latLongToCartesian(array[0], array[1]);
	}
	
	public static double[] latLongToCartesian(double lat, double lon){
		double[] cartesianArray = new double[3];
		double clat = lat * Math.PI / 180.0;
		double clon= lon * Math.PI / 180.0;
		cartesianArray[0] = Math.cos(clat) * Math.cos(clon);
		cartesianArray[1] = Math.cos(clat) * Math.sin(clon);
		cartesianArray[2] = Math.sin(clat);
		return cartesianArray;
	}
	
	public static double[] cartesianToLatLong(double[] cartesianArray){
		double[] coord = new double[2];
		double hyp = Math.sqrt(cartesianArray[0]*cartesianArray[0]+cartesianArray[1]*cartesianArray[1]);
		coord[1] = Math.atan2(cartesianArray[1], cartesianArray[0]);
		coord[0] = Math.atan2(cartesianArray[2], hyp);
		coord[1] = coord[1] * 180.0 / Math.PI;
		coord[0] = coord[0] * 180.0 / Math.PI;
		return coord;
	}

        public String getTrixel ( ) { if ( trixel == null ) trixel = getTrixel( value[0], value[1] ); return trixel; }
    
        public static String getTrixel ( double[] array ) { return getTrixel( array[0], array[1] ); }
        
        public static String getTrixel ( Double lat , Double lon )  {
                if ( lat == 0.0 ) lat = 0.25;
                if ( lat == -90.0 ) lat = -89.75;
                if ( lat == 90.0 ) lat = 89.75;
                if ( lon == 0.0 ) lon = 0.25;
                if ( lon == -180.0 ) lon = -179.75;
                if ( lon == 180.0 ) lon = 179.75;
                try { 
                   String value = spindex.lookup( lon , lat );
                   return value;
                } catch ( Exception ex ) { return null; }
	}
                
	public static Double getCatLatitude ( String cat ) {
                 try { 
                	 if(lat.containsKey(cat)) return(lat.get(cat)); else {
                  		lat.put(cat, spindex.idToPoint(cat).dec());
                   		return spindex.idToPoint(cat).dec();
                	 }
                 } catch ( Exception ex ) { return null; }
	}
	
	public static Double getCatLongitude ( String cat ) {
                 try {
                	if(lon.containsKey(cat)) return(lon.get(cat)); else
                	{
	                   double aux = spindex.idToPoint(cat).ra() ;
	                   if ( aux > 180.0 ) aux = -360.0 + aux;
                	   lon.put(cat, aux);
                	   return aux;
                	}
                 } catch ( Exception ex ) { return null; }
    	}

        public double getArea (  ) { return getArea( getTrixel() ); }

        public static double getArea ( String cat ) {
	    try {
	     Object v[] = HTMfunc.nameToTriangle(cat);
	     Domain d = new Domain();
	     Vector3d v1 = new Vector3d( ((double[])(v[0]))[0] , ((double[])(v[0]))[1], ((double[])(v[0]))[2] );
	     Vector3d v2 = new Vector3d( ((double[])(v[1]))[0] , ((double[])(v[1]))[1], ((double[])(v[1]))[2] );
	     Vector3d v3 = new Vector3d( ((double[])(v[2]))[0] , ((double[])(v[2]))[1], ((double[])(v[2]))[2] );
	     double v1lat = v1.dec();
	     double v2lat = v2.dec();
	     double v3lat = v3.dec();
	     double v1lon = v1.ra();
	     double v2lon = v2.ra();
	     double v3lon = v3.ra();
	     if(v1.ra() > 180.0) v1lon =  -360 + v1.ra();
	     if(v2.ra() > 180.0) v2lon =  -360 + v2.ra();
	     if(v3.ra() > 180.0) v3lon =  -360 + v3.ra();
	     double l1 = VincentyDistanceCalculator.getDistance(v1lat ,v1lon , v2lat , v2lon );
	     double l2 = VincentyDistanceCalculator.getDistance(v2lat ,v2lon , v3lat , v3lon );
	     double l3 = VincentyDistanceCalculator.getDistance(v3lat ,v3lon , v1lat , v1lon );
	     double p = (l1 + l2 + l3) / 2.0;
	     double area = Math.sqrt( p * (p-l1) * (p-l2) * (p-l3) );
	     return area;
	    } catch ( Exception ex ) { ex.printStackTrace(); return -1; }
	}

}
